// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
using System.Xml;
using System.Configuration;
using System.Web.Security;

namespace InterpriseSuiteEcommerceCommon.Integration.Interprise.Admin
{
    public class AuthorizationModule : IHttpModule
    {
        #region IHttpModule Members

        public void Dispose() {}

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(HandleBeginRequest);
        }

        private void HandleBeginRequest(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            if (app != null)
            {
                HttpContext ctx = app.Context;
                
                // other modules should handle the presence of this file
                FileInfo resourceInfo = new FileInfo(ctx.Request.PhysicalPath);
                if (resourceInfo.Exists)
                {
                    if (AuthorizationModuleConfiguration.Instance.ProtectedDirectories.ContainsKey(resourceInfo.Directory.FullName))
                    {
                        ProtectedDirectory dir = AuthorizationModuleConfiguration.Instance.ProtectedDirectories[resourceInfo.Directory.FullName];
                        if (dir != null)
                        {
                            // the directory is protected
                            if (!ctx.Request.IsAuthenticated)
                            {
                                if (!string.IsNullOrEmpty(dir.LoginUrl))
                                {
                                    bool isRequestedFileSameAsLogin = 
                                    ctx.Server.MapPath(dir.LoginUrl).Equals(ctx.Server.MapPath(ctx.Request.Url.LocalPath), StringComparison.InvariantCultureIgnoreCase);

                                    if (!isRequestedFileSameAsLogin)
                                    {
                                        ctx.RewritePath(dir.LoginUrl);
                                    }
                                }
                                else
                                {
                                    // throw an invalid access error
                                    ctx.Response.StatusCode = 403;
                                    ctx.Response.SuppressContent = true;
                                    ctx.Response.End();
                                }
                            }
                        }
                    }
                }
            }
        }

        #endregion
    }

    public class AuthorizationModuleConfigurationSectionHandler : IConfigurationSectionHandler
    {
        #region IConfigurationSectionHandler Members

        public object Create(object parent, object configContext, XmlNode section)
        {
            return AuthorizationModuleConfiguration.Configure(section);
        }

        #endregion
    }

    public class AuthorizationModuleConfiguration
    {
        private static AuthorizationModuleConfiguration _config;
        public Dictionary<string, ProtectedDirectory> _protectedDirectories = new Dictionary<string, ProtectedDirectory>();

        private AuthorizationModuleConfiguration() { }

        public Dictionary<string, ProtectedDirectory> ProtectedDirectories
        {
            get { return _protectedDirectories; }
        }

        
        public static AuthorizationModuleConfiguration Instance
        {
            get
            {
                if (_config == null)
                {
                    _config = ConfigurationManager.GetSection("ISEAuthorization") as AuthorizationModuleConfiguration;
                }

                return _config;
            }
        }

        public static AuthorizationModuleConfiguration Configure(XmlNode section)
        {
            AuthorizationModuleConfiguration authConfig = new AuthorizationModuleConfiguration();
            
            XmlNodeList protectedDirectoryNodes = section.SelectNodes("protectedDirectory");
            foreach (XmlNode protectedDirectoryNode in protectedDirectoryNodes)
            {
                ProtectedDirectory protedtedDir = ExtractProtectedDirectoryConfiguration(protectedDirectoryNode);
                if (protedtedDir != null)
                {
                    authConfig.ProtectedDirectories.Add(protedtedDir.Path, protedtedDir);
                }
            }

            return authConfig;
        }

        private static ProtectedDirectory ExtractProtectedDirectoryConfiguration(XmlNode protectedDirectoryNode)
        {
            XmlAttributeCollection attributes = protectedDirectoryNode.Attributes;
            string dirPath = attributes["path"] != null ? attributes["path"].Value : string.Empty;
            dirPath = HttpContext.Current.Server.MapPath(dirPath);
            if (!Directory.Exists(dirPath)) throw new ArgumentException("Protected directory does not exist!!!");

            string loginUrl = attributes["loginUrl"] != null ? attributes["loginUrl"].Value : string.Empty;
            bool protectAllFiles = attributes["protectAllFiles"] != null ? bool.TryParse(attributes["protectAllFiles"].Value, out protectAllFiles) && protectAllFiles : true;

            ProtectedDirectory dir = new ProtectedDirectory(dirPath, protectAllFiles);
            dir.LoginUrl = loginUrl;

            return dir;
        }

    }

    public class ProtectedDirectory
    {
        #region Variable Declaration

        private string _loginUrl;
        private string _path;
        private bool _protectAllFiles;

        #endregion

        public ProtectedDirectory(string path, bool protectAllFiles)
        {
            _path = path;
            _protectAllFiles = protectAllFiles;
        }

        public string LoginUrl
        {
            get { return _loginUrl; }
            set { _loginUrl = value; }
        }

        public string Path
        {
            get { return _path; }
        }

        public bool ProtectAllFiles
        {
            get { return _protectAllFiles; }
        }
    }
}
